#include "GY_GraphicsBezierItem.h"
#include <QDebug>

GY_GraphicsBezierItem::GY_GraphicsBezierItem(const QString &guid, QGraphicsItem *parent)
   :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图元类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("BezierItem"));
    initializationPropertyInfo();
    //获取初始化编辑点数据
    QMap<QVariant,QPointF> editPoints = {
        {"Point1",m_PropertyInfoMap["Point1"].propertyValue.toPointF()},
        {"Ctrl1",m_PropertyInfoMap["Ctrl1"].propertyValue.toPointF()},
        {"Ctrl2",m_PropertyInfoMap["Ctrl2"].propertyValue.toPointF()},
        {"Point2",m_PropertyInfoMap["Point2"].propertyValue.toPointF()}
    };
    updatePath();
    this->setEditPointF(editPoints);
}

void GY_GraphicsBezierItem::initializationPropertyInfo()
{
    GY_PropertyInfo ObjectName(this);
    ObjectName.propertyName = "ObjectName";
    ObjectName.propertyValue = QString();
    ObjectName.updateType = Update|OrdinaryAttributes;
    ObjectName.propertyType = QStringPropertyType;
    ObjectName.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updateObjectName;
    m_PropertyInfoMap.insert("ObjectName",ObjectName);
    m_PropertyInfoMap[ObjectName.propertyName].setConnect();

    GY_PropertyInfo IsVisible(this);
    IsVisible.propertyName = "IsVisible";
    IsVisible.propertyValue = true;
    IsVisible.updateType = Update|OrdinaryAttributes;
    IsVisible.propertyType = BoolPropertyType;
    IsVisible.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updateIsVisible;
    m_PropertyInfoMap.insert("IsVisible",IsVisible);
    m_PropertyInfoMap["IsVisible"].setConnect();

    GY_PropertyInfo IsAntialiased(this);
    IsAntialiased.propertyName = "IsAntialiased";
    IsAntialiased.propertyValue = true;
    IsAntialiased.updateType = Update|OrdinaryAttributes;
    IsAntialiased.propertyType = BoolPropertyType;
    IsAntialiased.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updateIsAntialiased;
    m_PropertyInfoMap.insert("IsAntialiased",IsAntialiased);
    m_PropertyInfoMap["IsAntialiased"].setConnect();

    GY_PropertyInfo PenAttributes(this);
    PenAttributes.propertyName = "PenAttributes";
    PenAttributes.propertyValue = false;
    PenAttributes.updateType = Update|OrdinaryAttributes;
    PenAttributes.propertyType = BoolPropertyType;
    PenAttributes.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePenAttributes;
    m_PropertyInfoMap.insert("PenAttributes",PenAttributes);
    m_PropertyInfoMap["PenAttributes"].setConnect();

    GY_PropertyInfo PenColor(this);
    PenColor.propertyName = "PenColor";
    PenColor.propertyValue = QColor();
    PenColor.updateType = Update|OrdinaryAttributes;
    PenColor.propertyType = ColorPropertyType;
    PenColor.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePenColor;
    m_PropertyInfoMap.insert("PenColor",PenColor);
    m_PropertyInfoMap[PenColor.propertyName].setConnect();

    GY_PropertyInfo PenOpacity(this);
    PenOpacity.propertyName = "PenOpacity";
    PenOpacity.propertyValue = 1;
    PenOpacity.updateType = Update|OrdinaryAttributes;
    PenOpacity.propertyType = QrealPropertyType;
    PenOpacity.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePenOpacity;
    m_PropertyInfoMap.insert("PenOpacity",PenOpacity);
    m_PropertyInfoMap[PenOpacity.propertyName].setConnect();

    GY_PropertyInfo LineStyle(this);
    LineStyle.propertyName = "LineStyle";
    LineStyle.propertyValue = QVariant();
    LineStyle.updateType = Update|OrdinaryAttributes;
    LineStyle.propertyType = LineStylePropertyType;
    LineStyle.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updateLineStyle;
    m_PropertyInfoMap.insert("LineStyle",LineStyle);
    m_PropertyInfoMap[LineStyle.propertyName].setConnect();

    GY_PropertyInfo precision(this);
    precision.propertyName = "Precision";
    precision.propertyValue = int(10);
    precision.updateType = Update|OrdinaryAttributes;
    precision.propertyType = IntPropertyType;
    precision.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePrecision;
    m_PropertyInfoMap.insert("Precision",precision);
    m_PropertyInfoMap["Precision"].setConnect();

    GY_PropertyInfo point1(this);
    point1.propertyName = "Point1";
    point1.propertyValue = QPointF(0,0);
    point1.updateType = Update|PointOfRelative;
    point1.propertyType = PointPropertyType;
    point1.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePoint;
    m_PropertyInfoMap.insert("Point1",point1);
    m_PropertyInfoMap["Point1"].setConnect();

    GY_PropertyInfo ctrl1(this);
    ctrl1.propertyName = "Ctrl1";
    ctrl1.propertyValue = QPointF(100,-100);
    ctrl1.updateType = Update|PointOfRelative;
    ctrl1.propertyType = PointPropertyType;
    ctrl1.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePoint;
    m_PropertyInfoMap.insert("Ctrl1",ctrl1);
    m_PropertyInfoMap["Ctrl1"].setConnect();

    GY_PropertyInfo ctrl2(this);
    ctrl2.propertyName = "Ctrl2";
    ctrl2.propertyValue = QPointF(200,200);
    ctrl2.updateType = Update|PointOfRelative;
    ctrl2.propertyType = PointPropertyType;
    ctrl2.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePoint;
    m_PropertyInfoMap.insert("Ctrl2",ctrl2);
    m_PropertyInfoMap["Ctrl2"].setConnect();

    GY_PropertyInfo point2(this);
    point2.propertyName = "Point2";
    point2.propertyValue = QPointF(300,0);
    point2.updateType = Update|PointOfRelative;
    point2.propertyType = PointPropertyType;
    point2.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsBezierItem::updatePoint;
    m_PropertyInfoMap.insert("Point2",point2);
    m_PropertyInfoMap["Point2"].setConnect();
}

bool GY_GraphicsBezierItem::updatePrecision(const QString &name, const QVariant &value)
{
    //当精度过于小时，因为曲线变直线，所以等比例的点位连起来可能直线长度比例有差距
    if(!value.canConvert<int>())
    {
        return false;
    }
    //限定value值在1~100之间
    if(value.toInt() < 1) {
        m_PropertyInfoMap[name].propertyValue = 1;
    }else if(value.toInt() > 100){
        m_PropertyInfoMap[name].propertyValue = 100;
    }else {
        m_PropertyInfoMap[name].propertyValue = value;
    }
    updatePath();
    return true;
}

bool GY_GraphicsBezierItem::updatePoint(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=this->mapFromScene(value.toPointF());
    //设置编辑点
    this->setEditPointF(name,this->mapFromScene(value.toPointF()));
    updatePath();
    return true;
}

void GY_GraphicsBezierItem::updatePath()
{
    //获取存储属性信息
    QPointF point1 = m_PropertyInfoMap.value("Point1").propertyValue.toPointF();
    QPointF point2 = m_PropertyInfoMap.value("Point2").propertyValue.toPointF();
    QPointF ctrl1 = m_PropertyInfoMap.value("Ctrl1").propertyValue.toPointF();
    QPointF ctrl2 = m_PropertyInfoMap.value("Ctrl2").propertyValue.toPointF();
    //分为precision条折线
    int precision = m_PropertyInfoMap.value("Precision").propertyValue.toInt();

    //绘制三阶贝塞尔曲线
    QPainterPath path;
    path.moveTo(point1);
    path.cubicTo(ctrl1,ctrl2,point2);

    //用lineto连接所有点
    QPainterPath Path;
    //获取一段所占百分比
    qreal t = qreal(1)/precision;
    //Path设置起始点
    Path.moveTo(point1);
    //连接中间各点，用折线表示贝塞尔曲线
    for(int i=1;i<precision;i++) {
        //pointAtPercent获取每个线段百分比所在的点位置
        Path.lineTo(path.pointAtPercent(t*i));
    }
    //连接最后一个点
    Path.lineTo(point2);
    this->setPath(Path);
}



